/* 
 *  <copyright file="SoundGameService.cs" company="Wesley Jowitt">
 *  
 *  SobrietyEngine: Copyright (c) 2011 Wesley Jowitt
 *  
 *  This software is distributed under a software license.
 *   * As of the creation time of this file, the license in use is the Microsoft Permissive License (Ms-PL) 
 *    * The license can be viewed at:
 *     * License.Txt in the root folder of this project
 *      * http://sobrietyengine.codeplex.com/license
 *       * http://www.microsoft.com/opensource/licenses.mspx
 *       
 *  </copyright>
 *   */

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;

using SobrietyEngine.Events;
using SobrietyEngine.Sound.Events;

/*
 * This guy still contains hard coded badness from initial creation. Needs much work.
 * 
 * 
 * 
 */
namespace SobrietyEngine.Sound
{
    public class SoundGameService:GameComponent, IEventListener
    {
        EventRouterGameService EventRouter = null;

        Boolean doAudio = true;

        public Boolean DoAudio
        {
            get { return doAudio; }
            set { doAudio = value; }
        }

        AudioEngine audioEngine;
        WaveBank waveBank;
        SoundBank soundBank;
        AudioCategory musicCategory;
        AudioCategory defaultCategory;

        Boolean playingMusic = false;
        List<Cue> musicPlaylist = new List<Cue>();
        Cue currentSong;
        int curSongInd = 0;

        Dictionary<string, Cue> cueMap = new Dictionary<string, Cue>();

        private float musicVolume = 0.4f;

        public float MusicVolume
        {
            get { return musicVolume; }
            set {  }
        }
        private float defaultVolume = 0.9f;

        public float DefaultVolume
        {
            get { return defaultVolume; }
            set {  }
        }

        public SoundGameService(Game game):base(game)
        {
            game.Services.AddService(typeof(SoundGameService), this);
        }

        public override void Initialize()
        {
            base.Initialize();
            if (doAudio)
            {
                //textQueue = new Queue<DrawableText>();
                EventRouter = (EventRouterGameService)Game.Services.GetService(typeof(IEventRouter));
                RegisterEventListeners();
            }
        }

        public virtual void RegisterEventListeners()
        {
            EventRouter.AddEventListener(typeof(PlaySound), this);
        }

        public virtual void UnregisterEventListeners()
        {
            EventRouter.RemoveEventListener(typeof(PlaySound), this);
        }

        public void LoadBank(String audioEngineXGS, String soundBankXSB, string waveBankXWB)
        {
            if (doAudio)
            {
                audioEngine = new AudioEngine(audioEngineXGS);
                soundBank = new SoundBank(audioEngine, soundBankXSB );
                waveBank = new WaveBank(audioEngine, waveBankXWB);

                if (audioEngine == null || soundBank == null || waveBank == null)
                {
                    doAudio = false;
                    this.Enabled = false;
                    EventRouter.RemoveEventListener(this);
                }

                musicCategory = audioEngine.GetCategory("Music");
                defaultCategory = audioEngine.GetCategory("Default");
                SetMusicVolume(musicVolume);
                SetSoundVolume(defaultVolume);
            }
        }

        public void SetMusicVolume(float zeroToTwo)
        {
            musicVolume = MathHelper.Clamp(zeroToTwo, 0.0f, 2.0f);
            musicCategory.SetVolume(musicVolume);
        }

        public void SetSoundVolume(float zeroToTwo)
        {
            defaultVolume = MathHelper.Clamp(zeroToTwo, 0.0f, 2.0f);
            defaultCategory.SetVolume(defaultVolume);
        }

        public void CreateMusicPlaylist(string[] trackNames)
        {
            if (doAudio)
            {
                if (musicPlaylist.Count > 0)
                    return;

                Random rand = new Random();
                //make music playlist here
                foreach (String track in trackNames)
                {
                    musicPlaylist.Add(GetCue(track));
                }
                int firstSong = rand.Next(2);
                currentSong = musicPlaylist[firstSong];
                curSongInd = firstSong;
            }
        }

        public void StartMusicPlaylist()
        {
            if (doAudio)
            {
                try
                {
                    currentSong.Play();
                    playingMusic = true;
                }
                catch
                {
                    musicPlaylist.Clear();
                    playingMusic = false;
                }
                
            }
        }

        public void StopMusicPlaylist()
        {
            if (doAudio)
            {
                currentSong.Stop(AudioStopOptions.AsAuthored);
                playingMusic = false;
            }
        }

        public Cue Play(string cueName)
        {
            if (doAudio)
            {
                Cue cue = GetCue(cueName);
                if (cue != null)
                    cue.Play();
                return cue;
            }
            else
                return (Cue)null;
        }

        public void Play(string soundName, string cueName)
        {
            if (cueMap.ContainsKey(soundName))
            {
                cueMap[soundName].Stop(AudioStopOptions.Immediate);
                cueMap.Remove(soundName);                
            }
            Cue cue = Play(cueName);
            if (cue == null)
                return;
            cueMap.Add(soundName, cue);
        }

        public void Stop(string cueName)
        {
            if (doAudio)
            {
                if (cueMap.ContainsKey(cueName))
                {
                    cueMap[cueName].Stop(AudioStopOptions.Immediate);
                    cueMap.Remove(cueName);
                }
            }
        }

        public Cue GetCue(string cueName)
        {
            if (soundBank == null)
                return null;
            Cue cue = null;
            try
            {
                cue = soundBank.GetCue(cueName);
            }
            catch(Exception ex)
            {
                Logging.Logger.Error("SoundGameService::GetCue() -> could not find cue name " + cueName + " exception " + ex.Message);
            }
            return cue;
        }

        #region IEventListener Members


        void IEventListener.HandleEvent(Event e)
        {
            if (e.Type == typeof(PlaySound))
            {
                //get the name, play the sound
                Play(((PlaySound)e.Data).SoundName);
            }
        }

        #endregion



        public override void Update(GameTime gameTime)
        {
            if (doAudio)
            {                
                if (audioEngine == null)
                {
                    this.Enabled = false;
                    doAudio = false;
                    return;
                }
                audioEngine.Update();

                if (playingMusic && currentSong.IsStopped == true)
                {
                    ++curSongInd;
                    if (curSongInd >= musicPlaylist.Count)
                        curSongInd = 0;
                    currentSong = musicPlaylist[curSongInd];
                }
            }
            base.Update(gameTime);
        }
    }
}
